SRE-938: Fix npm vulnerabilities from the 2026-08-10 scan - #9182
Conversation
Refresh yarn.lock and bump the pins and resolutions holding vulnerable copies in place, closing 25 of the 26 open npm findings in this repo. Direct pins and resolutions: - dompurify 3.4.12 -> 3.4.13 (root resolution + @apps/hash-frontend) - js-yaml 4.3.0 -> 4.3.1 (@apps/hash-api, @local/repo-chores, @tests/hash-playwright, @redocly/openapi-core/js-yaml resolution) - nanoid 3.3.11 -> 3.3.17 (@apps/hash-api) - postcss 8.5.18 -> 8.5.25 (both next/postcss and postcss@npm:8.5.14 resolutions; Renovate bumped only the first) Re-resolved transitively, no manifest change needed: - brace-expansion 1.1.17/2.1.3/5.0.8 -> 1.1.18/2.1.4/5.0.9 - fast-uri 3.1.4 -> 3.1.5 - hono 4.12.29 -> 4.13.0 - ip-address 10.2.0 -> 10.4.0 - js-yaml 3.15.0 -> 3.15.1 - nanoid 3.3.16 -> 3.3.17, 5.1.6 -> 5.1.16 - postcss 8.5.22 -> 8.5.25 - undici 7.28.0 -> 7.29.0 Supersedes #9173, #9175, #9180 and #9181, none of which regenerated the lockfile.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9182 +/- ##
=======================================
Coverage 59.58% 59.58%
=======================================
Files 1419 1419
Lines 138220 138220
Branches 6549 6549
=======================================
+ Hits 82355 82357 +2
+ Misses 54801 54799 -2
Partials 1064 1064 Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
PR SummaryLow Risk Overview Manifest updates move Reviewed by Cursor Bugbot for commit 8ea6bc0. Bugbot is set up for automated code reviews on this repo. Configure here. |
Benchmark results
|
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2002 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1002 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 3314 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 1527 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 2078 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 1033 | Flame Graph |
policy_resolution_medium
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 102 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 269 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 108 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 133 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 63 | Flame Graph |
policy_resolution_none
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 8 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 3 | Flame Graph |
policy_resolution_small
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 26 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 94 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 27 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 66 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 29 | Flame Graph |
read_scaling_complete
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id;one_depth | 1 entities | Flame Graph | |
| entity_by_id;one_depth | 10 entities | Flame Graph | |
| entity_by_id;one_depth | 25 entities | Flame Graph | |
| entity_by_id;one_depth | 5 entities | Flame Graph | |
| entity_by_id;one_depth | 50 entities | Flame Graph | |
| entity_by_id;two_depth | 1 entities | Flame Graph | |
| entity_by_id;two_depth | 10 entities | Flame Graph | |
| entity_by_id;two_depth | 25 entities | Flame Graph | |
| entity_by_id;two_depth | 5 entities | Flame Graph | |
| entity_by_id;two_depth | 50 entities | Flame Graph | |
| entity_by_id;zero_depth | 1 entities | Flame Graph | |
| entity_by_id;zero_depth | 10 entities | Flame Graph | |
| entity_by_id;zero_depth | 25 entities | Flame Graph | |
| entity_by_id;zero_depth | 5 entities | Flame Graph | |
| entity_by_id;zero_depth | 50 entities | Flame Graph |
read_scaling_linkless
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | 1 entities | Flame Graph | |
| entity_by_id | 10 entities | Flame Graph | |
| entity_by_id | 100 entities | Flame Graph | |
| entity_by_id | 1000 entities | Flame Graph | |
| entity_by_id | 10000 entities | Flame Graph |
representative_read_entity
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1
|
Flame Graph |
representative_read_entity_type
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| get_entity_type_by_id | Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba
|
Flame Graph |
representative_read_multiple_entities
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_property | traversal_paths=0 | 0 | |
| entity_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=0 | 0 | |
| link_by_source_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true |
scenarios
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| full_test | query-limited | Flame Graph | |
| full_test | query-unlimited | Flame Graph | |
| linked_queries | query-limited | Flame Graph | |
| linked_queries | query-unlimited | Flame Graph |
Requested by Tim Diekmann · Slack thread
🌟 What is the purpose of this PR?
Closes 25 of the 26 open npm vulnerability findings the 2026-08-10 weekly scan reported against this repo, in one PR, and supersedes four Renovate security PRs that cannot merge.
Before:
yarn.lockcarried vulnerable copies of nine packages. Most of them are transitive dependencies whose parents' semver ranges already allow a patched release — they were simply never re-resolved. The rest were held down by direct version pins and by rootresolutionsentries.After: the lockfile has been re-resolved and deduped, and the four pins/resolutions that were blocking the remaining upgrades have been moved. Every vulnerable version listed below is now absent from
yarn.lock— not merely accompanied by a newer entry (see the gone-check below).Why this replaces the four Renovate PRs
#9173(postcss),#9175(js-yaml),#9180(dompurify) and#9181(nanoid) each changepackage.jsonand leaveyarn.lockuntouched, so every Yarn step in CI aborts. Renovate's own artifact-update comment on each names the cause: this repo declarespackageManager: yarn@4.16.0, but the Renovate runner's global Yarn is 1.22.22 with Corepack disabled, so it cannot write a Yarn Berry lockfile. This is the same standing runner defect first seen oninternal-sites(#198/#199/#200) on 2026-08-06; it is now reproducing here. Fixing the runner is out of scope for this PR and is worth its own ticket.Two of them also needed correcting, not just relocking:
#9173is incomplete. The rootpackage.jsonhas two postcss resolutions,next/postcssandpostcss@npm:8.5.14. The PR bumps only the first, so the vulnerable 8.5.18 copy would have survived and GHSA-fxqj-rqcc-2cmp would have stayed open. Both are moved here.#9181takes two majors. It moves@apps/hash-api's exactnanoidpin from 3.3.11 straight to 5.1.16. nanoid 5 is ESM-only (nomain, no CJS entry point) with a Node ≥18 floor, whereas 3.3.17 keeps the dualmain: index.cjs/module: index.jslayout that 3.3.11 has. 3.3.17 closes both nanoid advisories on its own, so there is no reason to take a major inside a security fix — and it lets the pinned copy collapse into the same lockfile entry as the transitivenanoid@npm:^3.0.0/^3.3.16range instead of adding a third one. If nanoid 5 is wanted in hash-api, that belongs in a separate non-security PR.🔗 Related links
postcssto v8.5.23 [SECURITY] #9173, Update npm packagejs-yamlto v4.3.1 [SECURITY] #9175, Update npm packagedompurifyto v3.4.13 [SECURITY] #9180, Update npm packagenanoidto v5 [SECURITY] #9181🚫 Blocked by
🔍 What does this change?
Manifest changes — direct pins and resolutions that were blocking a patched resolution:
dompurifyresolutions,@apps/hash-frontendjs-yaml@apps/hash-api,@local/repo-chores,@tests/hash-playwright,@redocly/openapi-core/js-yamlresolutionnanoid@apps/hash-apipostcssnext/postcssandpostcss@npm:8.5.14resolutionsLockfile-only changes — transitive dependencies whose parents already admitted the fix, so no manifest change was needed:
brace-expansionfast-urihonoip-addressjs-yamlnanoidpostcssundiciRegenerated with
yarn installfollowed byyarn dedupe --strategy highest;yarn lint:yarn-deduplicatereports nothing left to dedupe. Targets are the highest release the repo'snpmMinimalAgeGate: 5dadmits, which is why postcss stops at 8.5.25 rather than 8.5.26, hono at 4.13.0 rather than 4.13.1, nanoid at 3.3.17 rather than 3.3.18 and ip-address at 10.4.0 rather than 10.5.0. No gate override was needed — every version above is more than five days old.Why the resolutions stay resolutions
Per the "bump the pinning parent before adding or keeping an override" rule, each remaining override was re-checked against the registry:
next/postcss—next15.5.x still exact-pinspostcss8.4.31 in every release up to the current 15.5.23. Onlynext16.3.0 moves to 8.5.23, and that is a major upgrade of Next, not a security fix.postcss@npm:8.5.14— this descriptor comes from PandaCSS (@pandacss/core,@pandacss/generator,@pandacss/node,@pandacss/postcss). The current latest, 1.12.0, still exact-pinspostcss8.5.14.@redocly/openapi-core/js-yaml— the repo is on@redocly/openapi-core@^1.34.6. The newest 1.x, 1.34.18, pinsjs-yaml4.3.0, which is itself the vulnerable version; only the 2.x major moves tojs-yaml ^5.2.2.dompurify— kept global becausemonaco-editor@0.55.1pulls indompurify3.2.7, which is affected by this advisory and several older ones. The resolution collapses it onto the patched copy.Gone-check
Every vulnerable version has zero
resolution:entries in the newyarn.lock:The
yarn.lockdiff is +48/−68: entries are removed, not merely added. Re-running the whole lockfile through npm's bulk advisory endpoint before and after the change shows 23 advisory rows closed and zero new ones.Advisories closed
brace-expansion1.1.17, 2.1.3, 5.0.8fast-uri3.1.4ip-address10.2.0js-yaml3.15.0, 4.3.0nanoid3.3.11, 5.1.6nanoid3.3.11, 3.3.16undici7.28.0dompurify3.4.12hono4.12.29hono4.12.29hono4.12.29ip-address10.2.0ip-address10.2.0postcss8.5.18, 8.5.22undici7.28.0undici7.28.0undici7.28.0undici7.28.0hono4.12.29Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
esbuild0.27.7 (GHSA-g7r4-m6w7-qqqr, low) is the one finding this PR does not close, and it is deliberately left alone.tsup's latest release (8.5.1) still declaresesbuild: ^0.27.0, andvite@7.3.5andstorybook9.x/10.x also cap at^0.27.0, so 0.28.1 is unreachable without forcing an override past several parents' declared ranges. Unchanged from the 2026-07-20 assessment.🐾 Next steps
postcssto v8.5.23 [SECURITY] #9173, Update npm packagejs-yamlto v4.3.1 [SECURITY] #9175, Update npm packagedompurifyto v3.4.13 [SECURITY] #9180 and Update npm packagenanoidto v5 [SECURITY] #9181 once this is green.internal-siteswill land broken and need this same manual repair. Worth its own ticket.🛡 What tests cover this?
The existing CI suite. There are no source changes — only dependency versions — so the signal is that lint, typecheck, unit, integration and the Docker/Vercel builds all still pass against the re-resolved tree.
❓ How to test this?
yarn install --immutable— it should complete without rewriting the lockfile.yarn lint:yarn-deduplicate— it should report nothing to dedupe.yarn.lockfor any of the versions in the gone-check table above — there should be no matches.